class Tool {
    constructor() {}

    // 下载文件 -> downPath是全路径，包括(文件名和文件格式)
    downFileToDir(downUrl, downPath) {
        return new Promise((resolve, reject) => {
            if (!downUrl || !downPath) {
                reject(new Error(`downFileToDir 参数不全: ${downUrl}/${downPath}`));
                return;
            }
            let canUse = this.isToolCanUse();
            if (!canUse) { // 通知调用者，调用不成功
                reject(new Error("函数不能被调用，没有通过 isToolCanUse() 验证"));
                return false;
            }

            let 
                totalLen = 9999,
                progress = 0,
                layaresponse;
            var stream = codeMain.fs.createWriteStream(downPath);
            codeMain.layarequest(downUrl).on('error', function(err) {
                console.log("tool down err:" + err);
                reject(err);
            }).on("data", function(data) {
                progress += data.length;
                let downPercent = (progress / totalLen * 100).toFixed(3);
                console.log(`%c down: ${downPercent}`, "color: red;");
            }).on("response", function(response) {
                layaresponse = response;
                totalLen = response.caseless.dict['content-length'];
            }).pipe(stream).on('close', function() {
                if (layaresponse.statusCode == 200) {
                    resolve();
                } else {
                    reject(new Error("下载失败，连接关闭"));
                }
            });
        });
    }

    // 解压zip
    extractZipFile(zipPath, extractDir) {
        return new Promise((resolve, reject) => {
            if (!zipPath || !extractDir) {
                reject(new Error(`extractZipFile 参数不全: ${zipPath}/${extractDir}`));
                return false;
            }
            let canUse = this.isToolCanUse();
            if (!canUse) { // 通知调用者，调用不成功
                reject(new Error("函数不能被调用，没有通过 isToolCanUse() 验证"));
                return false;
            }

            // codeMain.layaunzip 解压文件的时候经常会报错，不再使用该类库
            // codeMain.fs.createReadStream(zipPath).pipe(codeMain.layaunzip.Extract({
            //     path: extractDir
            // }).on("error", (e) => {
            //     reject(new Error(e));
            // }).on("close", (e) => {
            //     resolve();
            // }));
            layaUnzipFileHandler(zipPath, extractDir, (error, stdout, stderr) => {
                if (error || stderr) {
                    reject(error || stderr);
                    return;
                }
                resolve();
            });
        });
    }

    // 下载并解压zip包 -> 解压完成后会删掉zip包
    downAndExtractZip(downUrl, extractDir) {
        return new Promise((resolve, reject) => {
            if (!downUrl || !extractDir) {
                reject(new Error(`downAndExtractZip 参数不全: ${downUrl}/${extractDir}`));
                return false;
            }
            let canUse = this.isToolCanUse();
            if (!canUse) { // 通知调用者，调用不成功
                reject(new Error("函数不能被调用，没有通过 isToolCanUse() 验证"));
                return false;
            }

            const 
                zipName = "maker.zip",
                zipPath = codeMain.path.join(extractDir, zipName);
            // 如果文件夹不存在，创建文件夹
            codeMain.mkdirsSync(extractDir);
            this.downFileToDir(downUrl, zipPath).then(() => { // 下载成功
                return this.extractZipFile(zipPath, extractDir);
            }).then(() => { // 解压成功
                codeMain.fs.unlink(zipPath); // 删掉zip包
                setTimeout(() => {
                    resolve();
                }, 100);
            }).catch((e) => { // 失败
                reject(e);
            });
        });
    }

    // 压缩zip
    zipDir(sourceDir, zipName) {
        return new Promise((resolve, reject) => {
            if (!sourceDir || !zipName) {
                reject(new Error(`zipDir 参数不全: ${sourceDir}/${zipName}`));
                return false;
            }
            if (!zipName.endsWith(".zip")) {
                zipName += ".zip";
            }
            let canUse = this.isToolCanUse();
            if (!canUse) { // 通知调用者，调用不成功
                reject(new Error("函数不能被调用，没有通过 isToolCanUse() 验证"));
                return false;
            }
            // 压缩包放在文件夹所在目录的同级
            let zipDirPath = codeMain.path.dirname(sourceDir);
            if (!zipDirPath || this.zipDirPath === sourceDir) {
                reject(new Error("压缩包路径和被压缩目录同级"));
                return false;
            }

            // 压缩包路径
            let zipPath = codeMain.path.join(zipDirPath, zipName);
            var output = fs.createWriteStream(zipPath);
            var archive = codeMain.layazip;
            // 关闭事件仅在涉及文件描述符时触发
            output.on('close', function() {
                console.log(archive.pointer() + ' total bytes');
                console.log('归档程序已经完成，输出文件描述符已经关闭。');
                resolve(zipPath);
            });
            // 无论数据源是什么，当数据源耗尽时都会触发此事件。
            output.on('end', function() {
                console.log('所有文件压缩完成');
                resolve(zipPath);
            });
            // 捕获警告
            archive.on('warning', function(err) {
                if (err.code === 'ENOENT') {
                    console.warn("压缩: ", err);
                } else {
                    console.error(err);
                    reject(err);
                    throw err;
                }
            });
            // 明确的捕获错误
            archive.on('error', function(err) {
                console.error(err);
                reject(err);
                throw err;
            });
            // 压缩
            archive.pipe(output);
            // 从子目录中追加文件，将其内容放在存档的根目录中
            archive.directory(sourceDir, false);
            // 结束示例并防止进一步追加存档结构
            archive.finalize();
        });
    }

    // 构建html file对象，供上传时使用
    getFile(filePath) {
        if (!filePath) {
            throw new Error(`getFile 参数不全: ${filePath}`);
        }
        let canUse = this.isToolCanUse();
        if (!canUse) { // 通知调用者，调用不成功
            throw new Error("函数不能被调用，没有通过 isToolCanUse() 验证");
        }

        const encoding = null;
        let  
            _fileName = codeMain.path.basename(filePath),
            extname = codeMain.path.extname(_fileName),
            type;
        switch(extname) {
            case ".zip":
                type = "application/zip";
                break;
            case ".jpg":
                type = "image/jpeg";
                break;
            case ".png":
                type = "image/png";
                break;
            case ".mp3":
                type = "audio/mp3";
                break;
            case ".wav":
                type = "audio/wav";
                break;
            case ".ttf":
                type = "application/octet-stream";
                break;
            default:
                type = "";
        }
        let buffer = codeMain.fs.readFileSync(filePath, encoding);
        // if ((typeof buffer == 'string') && buffer.charCodeAt(0)==65279 && encoding=="utf8") { // windows第一位可能导致无法解析
        //     console.error("特殊处理windows");
        //     buffer = buffer.substr(1);
        // }
        let file = new File([buffer], _fileName, {type: type});
        return file;
    }

    /**
     * 获取音频长度
     * @param {*} filePath
     * @returns {number} 单位 s
     * - 如果传入的路径无法解析，则返回0
     */
    getAudioDuration(filePath) {
        return new Promise(function(resolve, reject) {
            if ("string" !== typeof filePath) {
                return resolve(0);
            }
            if (!filePath.endsWith(".mp3") && !filePath.endsWith(".wav")) {
                return resolve(0);
            }
            let timer;
            let audioEle = document.createElement("AUDIO");
            audioEle.id = "get_audio_duration_layabox_temp";
            audioEle.style = "z-index: -1; visible: none;";
            document.body.appendChild(audioEle);
            audioEle.onerror = function(e) {
                console.error(e);
                audioEle.remove();
                resolve(0);
                clearTimeout(timer);
            }
            audioEle.ondurationchange = function() {
                let duration = Math.round(audioEle.duration) || 1; // 如果时长不足0.5s，也设定为1s
                audioEle.remove();
                resolve(duration);
                clearTimeout(timer);
            }
            audioEle.autoplay = false;
            audioEle.controls = false;
            audioEle.src = filePath;
            timer = setTimeout(function() { // 如果 3s 后仍没有获取到音频时长，不再等待，返回0
                console.error("执行了timeout");
                resolve(0);
            }, 3000);
        });
    }

    /**
     * 获取图片的宽高
     * - 传过来的是HTML file对象
     */
    getImageWH(htmlImage) {
        return new Promise((resolve, reject) => {
            let timer;
            let reader = new FileReader();
            reader.onload = (e) => {
                let base64 = reader.result;
                let img = new Image();
                img.onload = () => {
                    clearTimeout(timer);
                    resolve({
                        width: img.width,
                        height: img.height
                    });
                }
                img.src = base64;
            }
            reader.readAsDataURL(htmlImage);
            timer = setTimeout(function() { // 如果 3s 后仍没有获取到音频时长，不再等待，返回0
                console.error("执行了timeout");
                reject();
            }, 5000);
        });
    }

    // 检查函数是否能够使用
    isToolCanUse() {
        if (typeof codeMain !== "undefined") {
            return true;
        }
        return false;
    }

    // numValue能不能转化为money
    isMoney(numValue) {
        if (!isFinite(numValue)) {
            return false;
        }
        return /^\d+(\.\d{1,2})?$/.test(numValue);
    }
}

module.exports = Tool;